Skip to content

fix(spv): compute required proof headers from actual header difficulties#4038

Closed
lionakhnazarov wants to merge 92 commits into
threshold-network:mainfrom
lionakhnazarov:feat/testnet4-deployment-support
Closed

fix(spv): compute required proof headers from actual header difficulties#4038
lionakhnazarov wants to merge 92 commits into
threshold-network:mainfrom
lionakhnazarov:feat/testnet4-deployment-support

Conversation

@lionakhnazarov

@lionakhnazarov lionakhnazarov commented Jun 12, 2026

Copy link
Copy Markdown
Collaborator

fix(spv): compute required proof headers from actual header difficulties

Problem

The SPV maintainer computed the number of block headers for a proof assuming every header carries the relay epoch difficulty: with txProofDifficultyFactor = 1 it always assembled a single-header proof. On testnet4 (BIP94), sweep transactions are regularly mined in minimum-difficulty (DIFF1) blocks, so the proof contained only a DIFF1 header. The Bridge skips DIFF1 headers when binding to the relay difficulty, finds no decisive header, and reverts with:

execution reverted: Not at current or previous difficulty

Because the error is deterministic, the maintainer crash-looped on the same transaction every cycle (error while maintaining SPV: ... restarting maintainer), and the affected wallet's main UTXO could never be registered on the host chain — blocking all subsequent sweeps for that wallet.

Fix

getProofInfo now mirrors the Bridge's BitcoinTx.determineRequestedDifficulty / evaluateProofDifficulty logic instead of assuming a fixed per-header difficulty:

  • walk headers forward from the proof start block,
  • skip leading minimum-difficulty headers, but only when both relay epoch difficulties are above minimum (so test/dev relays at difficulty 1 keep working),
  • bind the requested difficulty to the first decisive header matching the relay's current or previous epoch difficulty; if it matches neither, skip the transaction (the Bridge would revert),
  • accumulate headers (DIFF1 headers still contribute their work) until total observed difficulty reaches requestedDifficulty × txProofDifficultyFactor,
  • bound the walk by maxProofHeaders = 144 and report "wait for more confirmations" when the chain tip is reached first.

The old epoch-boundary block-count arithmetic is removed; epoch spans are handled implicitly by summing actual header difficulties.

Testing

  • TestGetProofInfo rewritten for the new semantics: current/previous-epoch proofs, epoch-spanning proofs with difficulty drop/raise, leading DIFF1 headers, relay at minimum difficulty, decisive-header mismatch, DIFF1 run exceeding the header bound, and chain tip reached early. Headers are generated with real compact-bits encoding (blockHeaderWithDifficulty).
  • go test ./pkg/maintainer/spv passes.
  • Verified live on the Sepolia/testnet4 stack: a sweep stuck for 10 days (876510fd...62c8, mined in a DIFF1 block at height 137542) was proven on the first cycle after deploying this fix — submitDepositSweepProof tx 0xfeeefad32c7116727949483edfb1e38f8117d923521fd3467886a05226b82577, status 1 — and the maintainer completed its round cleanly.

Notes

  • Requires a Bridge with DIFF1-aware determineRequestedDifficulty (deployed via the DIFF1 library upgrade); against an older Bridge the maintainer now skips such transactions instead of crash-looping.

Summary by CodeRabbit

Release Notes

  • New Features

    • Added Bitcoin testnet4 support with default Electrum endpoint configuration.
    • Introduced improved fee estimation with fallback confirmation targets.
    • Added Sepolia network contract deployments.
  • Improvements

    • Enhanced Bitcoin difficulty validation with preflight checks and configurable idle behavior on failures.
    • Improved SPV proof header traversal with difficulty matching.
    • Standardized Yarn 4.8.1 across build workflows and Docker images.
  • Configuration

    • Added IdleOnPreflightFailure option for Bitcoin difficulty maintainer.

lionakhnazarov and others added 30 commits May 23, 2026 09:55
- Introduced Testnet4 configuration in  with a new Electrum server URL.
- Updated  to include Testnet4 for Bitcoin networks.
- Added Testnet4 constant in  for better network identification.
- Adjusted test cases in  for improved readability.
- Updated Hardhat configuration files to streamline deployment processes and handle potential errors during verification.
…ort.json file

- Removed a defunct Thesis Electrum URL from the expected peers in .
- Deleted the  file as it is no longer needed, streamlining the project structure.
…ackage.json and yarn.lock for ECDSA and random-beacon
lionakhnazarov and others added 28 commits May 23, 2026 09:56
…ardhat-verify after Hardhat 3 upgrade, clarifying API compatibility
…ervers and adding error handling for integration tests
…tOwner function with governance checks and error handling
… addresses, transaction hashes, and gas usage metrics
withdrawRewards resolves the beneficiary via _currentAuthorizationSource().
Replace stale NOT MIGRATED / TokenStaking-only commentary with accurate
routing, delegated-setup divergence, TIP-092/100 reward halt context, and
future reactivation semantics.

Made-with: Cursor
…s and update Hardhat configuration for plugin compatibility
…resses, transaction hashes, and gas metrics for multiple contracts
…specific group parameters for improved deployment on testnets
…aintainer for handling preflight errors gracefully
…improved transaction confirmation reliability
…ficulty maintainer's pre-retarget validation for better handling of minimum-difficulty blocks
…resses, transaction hashes, and gas metrics for multiple contracts
…ic block sequence and simplifying timeout handling for better reliability
…n to ensure proper behavior when multiple members submit claims
The rebase used -X theirs to resolve conflicts, which silently dropped two
items that existed in both main and the pre-rebase branch:

- .github/workflows/contracts-ecdsa.yml: --compile-force-framework hardhat
  flag for slither
- solidity/ecdsa/package.json: get-func-name ^2.0.2 resolution
Mirrors recent dependabot bumps on main:
- handlebars 4.7.7 -> 4.7.9 (random-beacon threshold-network#3916, prototype pollution fix)
- immutable 4.0.0-rc.15 -> 4.3.8 (random-beacon threshold-network#3879)

Added as Yarn 4 resolutions in both random-beacon and ecdsa to keep parity
across solidity workspaces and avoid post-merge dependabot churn.
Duplicate Allowlist identifier in test imports broke both lint
(no-redeclare) and tsc (TS2300) builds on CI.
getProofInfo assumed every proof header carries the relay epoch difficulty,
so with txProofDifficultyFactor=1 it assembled single-header proofs. On
testnet4 (BIP94), sweeps mined in minimum-difficulty blocks produced proofs
containing only a DIFF1 header, which the Bridge rejects with "Not at
current or previous difficulty".

Mirror the Bridge's BitcoinTx logic instead: skip leading DIFF1 headers
when both relay epochs are above minimum, bind the requested difficulty to
the first decisive header matching the relay's current or previous epoch
difficulty, and accumulate headers until their total observed difficulty
covers requestedDifficulty * txProofDifficultyFactor.
@coderabbitai

coderabbitai Bot commented Jun 12, 2026

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

Pull request was closed or merged during review

📝 Walkthrough

Walkthrough

This PR updates Git/Yarn setup for CI, changes Bitcoin/Ethereum and maintainer proof handling, and reworks Solidity ECDSA and Random Beacon deployment, fixture, and test flows for Sepolia, allowlist defaults, and legacy TokenStaking compatibility.

Changes

CI and Yarn setup

Layer / File(s) Summary
Docs workflow rewiring
\.github/workflows/contracts-ecdsa-docs.yml, \.github/workflows/contracts-random-beacon-docs.yml
Docs jobs point to the local reusable Solidity docs workflow instead of the remote CI workflow.
Yarn install hardening
\.github/actions/setup-git-for-yarn/action.yml, \.github/workflows/contracts-ecdsa.yml, \.github/workflows/contracts-random-beacon.yml, \.github/workflows/npm-ecdsa.yml, \.github/workflows/npm-random-beacon.yml, solidity/ecdsa/Dockerfile, solidity/ecdsa/package.json, solidity/random-beacon/Dockerfile, solidity/random-beacon/package.json, solidity/ecdsa/.yarnrc.yml, solidity/random-beacon/.yarnrc.yml, solidity/ecdsa/.dockerignore, solidity/random-beacon/.dockerignore
Workflow install steps now use the Git wrapper action, Corepack, pinned Yarn 4.8.1, and immutable installs with cleaned Git/Yarn environment settings.
Reusable workflow and config wiring
\.github/workflows/reusable-solidity-docs.yml, solidity/ecdsa/hardhat.config.ts, solidity/random-beacon/hardhat.config.ts, solidity/ecdsa/.eslintignore, solidity/ecdsa/.gitignore, solidity/ecdsa/.prettierignore, solidity/random-beacon/.gitignore, solidity/random-beacon/.prettierignore, solidity/random-beacon/tsconfig.json, solidity/ecdsa/tsconfig.json
The reusable Solidity docs workflow, package metadata, and workflow/config files define callable inputs, publish behavior, and pinned Yarn/package resolution settings.

Bitcoin, Ethereum, and maintainer logic

Layer / File(s) Summary
Bitcoin network and Electrum mappings
config/_electrum_urls/testnet4, pkg/bitcoin/bitcoin.go, config/electrum_test.go, config/network/network.go, config/contracts.go
Bitcoin network enums, testnet4 Electrum defaults, and network-to-Electrum resolution now include testnet4.
Electrum fee fallback flow
pkg/bitcoin/electrum/electrum.go, pkg/bitcoin/electrum/electrum_integration_test.go, pkg/bitcoin/electrum/electrum_test.go
Fee estimation now tries fallback confirmation targets, and the Electrum integration tests accept testnet4, transient errors, and missing vectors.
Ethereum chain and TBTC parameter lookup
pkg/chain/ethereum/bitcoin_difficulty.go, pkg/chain/ethereum/ecdsa_dkg_validator_chain.go, pkg/chain/ethereum/ethereum.go, pkg/chain/ethereum/ethereum_integration_test.go, pkg/chain/ethereum/tbtc.go, cmd/start.go, config/config_test.go, test/config.json, test/config.toml, test/config.yaml, cmd/flags.go, cmd/flags_test.go
The Ethereum chain now fetches headers directly, waits for mined retarget transactions, skips transient provider errors, and can read optional EcdsaDkgValidator group parameters into TBTC initialization.
Difficulty proof and SPV updates
pkg/maintainer/btcdiff/bitcoin_difficulty.go, pkg/maintainer/btcdiff/bitcoin_difficulty_test.go, pkg/maintainer/btcdiff/config.go, pkg/maintainer/btcdiff/errors.go, pkg/maintainer/spv/bitcoin_chain_test.go, pkg/maintainer/spv/spv.go, pkg/maintainer/spv/spv_test.go
Bitcoin difficulty preflight validation, SPV proof traversal, and their tests now use header-walk logic and new idle-on-failure behavior.
Inactivity claim handling
pkg/tbtc/inactivity.go, pkg/tbtc/inactivity_test.go
Inactivity claim submission now retries by nonce observation, and tests cover stale-nonce and concurrent submission paths.
Coordination watcher tests
pkg/tbtc/coordination_test.go
The coordination window test now uses deterministic block heights and a single timeout path.

Solidity ECDSA and Random Beacon

Layer / File(s) Summary
ECDSA Hardhat config and package setup
solidity/ecdsa/hardhat.config.ts, solidity/ecdsa/package.json, solidity/ecdsa/tsconfig.json, solidity/ecdsa/types/chai.d.ts, solidity/ecdsa/types/TokenStaking.extensions.d.ts, solidity/ecdsa/contracts/WalletRegistry.sol
The ECDSA workspace now pins Yarn 4, adjusts dependencies, and resolves Random Beacon deployment paths and verification behavior conditionally.
ECDSA deployment scripts and artifacts
solidity/ecdsa/deploy/*, solidity/ecdsa/deployments/sepolia/*
ECDSA deployment scripts now skip local missing deployments, gate verification, and include Sepolia deployment artifacts for validator, wallet registry, staking, and related contracts.
ECDSA fixtures, tasks, and tests
solidity/ecdsa/tasks/initialize-wallet-owner.ts, solidity/ecdsa/test/*, solidity/ecdsa/test/fixtures/index.ts, solidity/ecdsa/test/utils/operators.ts
The ECDSA fixtures and tests now default to allowlist mode, expose legacy TokenStaking helpers, and add type declarations for the legacy contract methods.
Random Beacon workspace setup
solidity/random-beacon/.dockerignore, solidity/random-beacon/.gitignore, solidity/random-beacon/.prettierignore, solidity/random-beacon/.yarnrc.yml, solidity/random-beacon/Dockerfile, solidity/random-beacon/package.json, solidity/random-beacon/hardhat.config.ts, solidity/random-beacon/tsconfig.json
The Random Beacon workspace now pins Yarn 4, uses Node 18, and adjusts local ignore and configuration files for Sepolia deployments.
Random Beacon deployment scripts and artifacts
solidity/random-beacon/deploy/05_approve_random_beacon_in_token_staking.ts, solidity/random-beacon/deployments/sepolia/*
Random Beacon deployment scripts add conditional approval/authorization flows, and Sepolia deployment artifacts are added for the Random Beacon stack.
Random Beacon tests and legacy TokenStaking helpers
solidity/random-beacon/test/*, solidity/random-beacon/test/fixtures/index.ts, solidity/random-beacon/test/utils/operators.ts
Random Beacon tests move to legacy TokenStaking wrappers or are skipped, and fixtures now tolerate missing methods in staking variants.

Sequence Diagram(s)

sequenceDiagram
  participant Workflow as GitHub Actions workflow
  participant Git as setup-git-for-yarn
  participant Yarn as Corepack/Yarn 4.8.1
  participant Docs as reusable-solidity-docs
  Workflow->>Git: prepare safe git wrapper
  Workflow->>Yarn: enable and install dependencies
  Workflow->>Docs: call reusable docs workflow
  Docs->>Yarn: run hardhat docgen
Loading
sequenceDiagram
  participant Maintainer as SPV/Btcdiff maintainer
  participant Chain as Bitcoin chain
  participant Relay as LightRelay
  participant Config as IdleOnPreflightFailure
  Maintainer->>Chain: load headers and difficulty targets
  Chain->>Relay: validate pre-retarget difficulty
  Relay-->>Maintainer: ErrUniformPreRetargetDifficulty or proof data
  Maintainer->>Config: decide idle vs fail
Loading

Changes

Suggested reviewers

  • piotr-roslaniec
  • lrsaturnino

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Poem

A bunny hopped through CI light,
With Yarn 4 pinned just right.
🐇 Headers danced, then proofs took flight,
And Sepolia sparkled bright.
Legacy hops and fresh paths sing—
A tidy burrow, spring by spring.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
⚔️ Resolve merge conflicts
  • Resolve merge conflict in branch feat/testnet4-deployment-support

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants